Wafer roughness plot
1 Base function
1.1 Different \(\mu\) sampling points
Code
# 1. Read the Excel file into a DataFrame
df = pd.read_excel('data/base_function.xlsx', sheet_name=['base', 'M'])
# 2. Split the DataFrame into two separate DataFrames
base_df = df['base']
M_df = df['M'].sort_values(by='M')
# M_df = M_df[~M_df.isin([-0.002, 0.003]).any(axis=1)]
sorted_df = pd.DataFrame(columns=['mu','xaxis', 'yaxis', 'colors'])
# 3. Create x axis
xaxis = np.arange(-15.5, 16.5, 1)
plots = []
# 4. Iterate M dataframe
for i, (index, row) in enumerate(M_df.iterrows()):
# a. Plot raw sampling data
p = figure(title=str(f'M: {row.M}'), x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 250, height = 150)
new_axis = xaxis - row.M
p.line(new_axis, base_df[index], line_color='#9DD9C5', line_width=3)
p.circle(new_axis, base_df[index], size = 4)
vline = Span(location=0.0, dimension = 'height', line_color='#FEEED9', line_width=1)
p.add_layout(vline)
# b. Plot format
p.x_range = Range1d(-7, 7)
p.yaxis.ticker.desired_num_ticks = 4
p = plot_format(p, "Degrees", "Intensity", "bottom_left", "8pt", "8pt", "8pt")
plots.append(p)
# c. Create dataframe
sorted_df = sorted_df.append(pd.DataFrame({'mu':[row.M]*32,'xaxis':new_axis, 'yaxis':base_df[index], 'colors':new_colors[0:32]}), ignore_index=True)
grid_raw = gridplot(children = plots, ncols = 6, merge_tools=False)
show(grid_raw)1.2 Base function smoothing and interpolation
Code
# 5. Create interleaved plots
interleaved_plot = figure(title='Interleaved base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 700, height = 500)
smooth_plot = figure(title='Smooth base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 700, height = 500)
interpolated_plot = figure(title='Inteporlated base function points', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 700, height = 500)
# a. Define base_function and smooth df's
base_function_df = sorted_df.sort_values(by='xaxis')
diff = base_function_df['xaxis'].diff()
smooth_df = base_function_df[(diff >= 0.01) | (diff.isna())]
smooth_df = smooth_df.iloc[1:]
# b. Create non-smooth and smoot curve
interleaved_plot = figure(title='Interleaved base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips=[("index", "$index"), ("(x,y)", "($x, $y)")],
width=700, height=500)
smooth_plot = figure(title='Smooth base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips=[("index", "$index"), ("(x,y)", "($x, $y)")],
width=700, height=500)
# c. Plot points
for (plot, df, legend, color) in [(interleaved_plot, base_function_df, 'Non-smooth base function', '#9DC3E6'), (smooth_plot, smooth_df, 'Smooth base function', '#9D6C97')]:
# individual points
plot.circle(df.xaxis, df.yaxis, color=df.colors, size=6)
# smooth curve
plot.line(df['xaxis'], df['yaxis'], line_width=4, legend=legend, color=color)
# format
plot.xaxis.ticker.desired_num_ticks = 15
plot.y_range = Range1d(0, 45000)
plot = plot_format(plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
# d. Interpolation
x_base = np.arange(-15.5, 15.5001, 0.001)
pchip = PchipInterpolator(smooth_df['xaxis'], smooth_df['yaxis'])
y_base = pchip(x_base)
interpolated_plot.line(x=smooth_df['xaxis'], y=smooth_df['yaxis'], line_width = 5, legend = 'Smooth base function', color = '#9D6C97')
interpolated_plot.line(x_base, y_base, line_width = 5, color = '#9DD9C5', legend = 'Interpolated base function')
interpolated_plot.xaxis.ticker.desired_num_ticks = 15
interpolated_plot.y_range = Range1d(0, 45000)
interpolated_plot = plot_format(interpolated_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
base_function_grid = gridplot(children=[interleaved_plot, smooth_plot, interpolated_plot], ncols=3, merge_tools=False, width=420, height=350)
show(base_function_grid)2 Experimental rough data
Once the base function has been reconstructed from smooth experimental data, the next step is to use such function as a reference to compare it with rough data. This is illustrated in Figure 1. Notice how the base function (green) is sharper and with a higher amplitude than the experimental data (blue).
The problem to be solved is to calculate parameters to modify the base function in order to obtain the amplitude difference as well as the tails as observed from the rough data.

Code
from scipy.optimize import curve_fit
# Define base function using xinterp and yinterp
def base_function(x, *params):
return np.interp(x, x_base, y_base)
# Define function to fit to dataset1
def fit_function(x, a, b, c):
return a * base_function(x, b, c)
# Extract xaxis and yaxis from dataset1
rough_df = pd.read_excel('data/rough_samples.xlsx')
xdata = rough_df['xaxis']
ydata = rough_df['pt2e']
# Use curve_fit to find parameters that minimize the difference between the data and the model
params, _ = curve_fit(fit_function, xdata, ydata)
# Evaluate the fitted function using the optimal parameters
yfit = fit_function(x_base, *params)
fit_plot = figure(title='Fit plot', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 700, height = 500)
fit_plot.line(x_base, y_base, line_width = 5, color = '#9DD9C5')
# fit_plot.line(x_base, yfit, line_width = 4, color = '#9D6C97', line_dash="dotdash")
fit_plot.line(xdata, ydata, line_width = 5, color = '#9DC3E6')
fit_plot.circle(xdata, ydata, size = 8, color = '#9DC3E6', fill_color='#2F528F')
fit_plot = plot_format(fit_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
show(fit_plot)Code
def fit_function(x, a):
return a * base_function(x)
from scipy.optimize import curve_fit
xdata = rough_df['xaxis']
ydata = rough_df['pt2e']
params, _ = curve_fit(fit_function, xdata, ydata)
yfit = fit_function(x_base, *params)
fit_plot = figure(title='Fit plot', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
width = 700, height = 500)
fit_plot.line(x_base, y_base, line_width = 4, color = '#9DD9C5', legend = 'Base function', line_dash=[10, 5])
fit_plot.line(x_base, yfit, line_width = 4, color = '#9D6C97', legend = 'pt2 fitted function', line_dash="dotdash")
fit_plot.line(xdata, ydata, line_width = 5, color = '#9DC3E6', legend_label = 'pt2 line')
fit_plot.circle(xdata, ydata, size = 10, color = '#9DC3E6', fill_color='#2F528F', legend_label = 'pt2 points')
fit_plot = plot_format(fit_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
show(fit_plot)Code
from bokeh.palettes import Set3
# 1. Import data
rough_df = pd.read_excel('data/rough_samples.xlsx')
source_rough = ColumnDataSource(rough_df)
# # 2. Create plot
rough_plot = figure(x_axis_label='xaxis', y_axis_label='yaxis', width = 650, height = 400, tooltips = [("index", "$index"),("(x,y)", "($x, $y)")])
color_palette = Set3[len(rough_df.columns[1:])+1]
# a. iterate over the columns and add a line for each one
for i, col in enumerate(rough_df.columns[1:]):
rough_plot.line('xaxis', col, source=source_rough, color = color_palette[i], legend_label = str(col), line_width=4)
rough_plot.circle('xaxis', col, source=source_rough, color = color_palette[i], size=6)
rough_plot.line(x_base, y_base, line_width=4, color = color_palette[i+1], legend = 'Interpolated base function')
rough_plot = plot_format(rough_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "10pt")
show(rough_plot)3 Wafer 2 with rough areas
3.1 Calcute Aq, M and I values
Code
lendata = data.shape[0] - 1
angles = (np.linspace(0, (lendata - 1), lendata)) * (data[-1, 29] - data[-1, 28]) * (2 * np.pi / lendata / 360) + (data[-1, 28] + 9.5 + 180) * np.pi / 180
radii = (np.linspace(0, (lendata-1), lendata)) * (data[-1,31]-data[-1,30])/lendata + data[-1, 30]
Aq = []
M = []
intens = []
x = np.arange(1, 33)
datamat = data[:lendata,:] - 1
sx = np.arange(1, 32, 0.2)
for indx in range(lendata):
# a. Do PChip spline interpolation
diodes = datamat[indx,:]
pchip = PchipInterpolator(x, diodes)
sy = pchip(sx)
sy = 100 * sy / np.max(sy)
c = []
# b. Concatenation/histogram
for indx2 in range(len(sx)):
c.extend([indx2+1]*round(sy[indx2]))
stddev = np.std(c) / 5
Aq.append(1.02 * np.exp(1.987 * np.log(stddev) + 0.16))
M.append((np.mean(c) - 1) / 5 - 15.5)
intens.append(np.sum(sy))3.2 Non interpolated Plot
Code
# 1. Get x and y coordinates
xvals = radii * np.cos(angles) * 1e-3
yvals = radii * np.sin(angles) * 1e-3
zvals = Aq
# 2. Clamp values to max of 3
zvalscut = 3
zvalsnew = np.array(zvals)
zvalsnew[zvalsnew > zvalscut] = zvalscut
# 3. Make a df
index = np.arange(len(xvals))
df = pd.DataFrame({
'index':index,
'x': xvals*1000,
'y': yvals*1000,
'z': zvalsnew,
})
#| column: screen-inset-right
# 4. Rank_text
interval = alt.selection_interval()
rank_text = alt.Chart(df).mark_text(dx=20, dy=-5, align='left').encode(
x=alt.value(10), # x position of the text
y=alt.value(10), # y position of the text
text=alt.condition(
interval,
alt.Text('index:Q', format='.2f'), # display 'x' column for selected points
alt.value('') # display empty string for unselected points
),
color=alt.value('black'), # color of the text
fontSize = 5
)
# 5. Wafer plot
wafer_plot = alt.Chart(df).mark_circle().encode(
x='x:Q', y='y:Q',
color=alt.condition(
interval,
alt.Color('z:Q', scale=alt.Scale(scheme='turbo')),
alt.value('lightgray')
),
tooltip=['x', 'y', 'z', 'index']
).properties(height=400, width=400).add_selection(interval)
# create a table with the selected points
selected_points_table = alt.Chart(df).transform_filter(
interval
).mark_text().encode(
x=alt.value(0),
y=alt.Y('row_number:O', axis=None),
text='index:Q',
).transform_window(
row_number='row_number()'
).properties(
height=400,
width=50
)
# vertically concatenate the two charts
alt.hconcat(wafer_plot, selected_points_table)
Code
sorted_df